package org.bronycorps.mlptss.domain.model;

import java.util.ArrayList;
import java.util.List;

import org.bronycorps.mlptss.domain.model.event.StateChangeEvent;
import org.bronycorps.mlptss.domain.model.event.StateChangeEventListener;
import org.bronycorps.mlptss.domain.model.type.EnemyColor;
import org.bronycorps.mlptss.manager.EnemyFactory;
import org.bronycorps.mlptss.manager.preferences.AssetsConfiguration.EnemyConfiguration;
import org.bronycorps.mlptss.manager.preferences.GameConfiguration;
import org.bronycorps.mlptss.utils.AnimationCache;
import org.bronycorps.mlptss.utils.DrawableAnimation;

public class Enemy extends AbstractActorModel {

	public enum State {
		CHAIN_EXPLODE, EXPLODE, EXPLODE_NO_CHAIN, HIT, NORMAL
	}

	private int bubbleLife;

	private List<StateChangeEventListener> changeEventListeners = new ArrayList<StateChangeEventListener>();
	private EnemyColor life;
	private State state = State.NORMAL;
	private Enemytype type;

	public Enemy(EnemyConfiguration enemyConfig, EnemyColor enemyColor,
			boolean hasShield) {
		super();
		this.type = EnemyFactory.getEnemyType(enemyConfig, enemyColor);
		this.life = enemyColor;
		if (hasShield) {
			this.bubbleLife = GameConfiguration.getInstance().getShieldLife();
		}
	}

	public boolean addListener(StateChangeEventListener e) {
		return this.changeEventListeners.add(e);
	}

	public void breakShield() {
		this.bubbleLife = 0;
		setState(State.NORMAL);
	}

	private void fireStateChange() {
		for (StateChangeEventListener listener : this.changeEventListeners) {
			listener.onStateChange(new StateChangeEvent(this));
		}
	}

	public DrawableAnimation getBubbleAnimation() {
		return AnimationCache.getInstance().get(
				this.type.getPrefix() + this.life.suffix + "-bubble");
	}

	public DrawableAnimation getBubbleHitAnimation() {
		return AnimationCache.getInstance().get(
				this.type.getPrefix() + "hit-bubble");
	}

	public DrawableAnimation getDefaultAnimation() {
		return AnimationCache.getInstance().get(
				this.type.getPrefix() + this.life.suffix);
	}

	public DrawableAnimation getExplosionAnimation() {
		return AnimationCache.getInstance().get(
				this.type.getPrefix() + "explosion");
	}

	public DrawableAnimation getHitAnimation() {
		return AnimationCache.getInstance().get(this.type.getPrefix() + "hit");
	}

	public int getLife() {
		if (this.life != null) {
			return this.life.level;
		} else {
			return -1;
		}
	}

	public EnemyColor getLifeColor() {
		return this.life;
	}

	public State getState() {
		return this.state;
	}

	public Enemytype getType() {
		return this.type;
	}

	/**
	 * hit by a bullet
	 * 
	 * @param model
	 */
	public void hit(Bullet model) {

		hit(1);
	}

	/**
	 * hit in a chain explosion
	 * 
	 * @param model
	 */
	public void hit(Enemy model) {
		hit(2);
	}

	private void hit(int damage) {
		if (this.state == State.NORMAL || this.state == State.HIT) {
			if (this.bubbleLife > 0) {
				this.bubbleLife -= damage;
				setState(State.HIT);
			} else {
				this.life = EnemyColor.getNextColor(this.life, damage);
				if (this.life == null) {
					setState(State.EXPLODE);
				} else {
					setState(State.HIT);
				}
			}
		}
	}

	public boolean isBubble() {
		return this.bubbleLife > 0;
	}

	public boolean isExploding() {
		return (this.state == State.EXPLODE
				|| this.state == State.CHAIN_EXPLODE || this.state == State.EXPLODE_NO_CHAIN);
	}

	public boolean remove(StateChangeEventListener o) {
		return this.changeEventListeners.remove(o);
	}

	public void setState(State state) {
		this.state = state;
		fireStateChange();
	}

	public void terminate(boolean chainExplode) {
		setState(chainExplode ? State.EXPLODE : State.EXPLODE_NO_CHAIN);
	}
}
